package cn.javabb.common.exception;

import cn.javabb.common.enums.ResponseEnum;
import cn.javabb.common.exception.advice.ResultExceptionAdvice;
import cn.javabb.common.holder.RequestHolder;
import cn.javabb.common.model.ResponseModel;
import cn.javabb.common.utils.RequestUtil;
import cn.javabb.common.utils.ResultUtil;
import cn.javabb.common.utils.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.Objects;

/**
 * 全局异常处理器
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    private final static String ENV_PROD="pro";

    @Value("${spring.profiles.active}")
    private String profile;

    /**  参数错误  异常  */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //服务器返回500
    public ResponseModel bindException(BindException e){
        log.error("参数绑定校验异常", e);
        BindingResult bindingResult = e.getBindingResult();
        return ResponseModel.Failure(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()
                , ResponseEnum.PARAM_ERROR.getCode());
    }
    /**    自定义异常，继承的Exception需要实现 setCode     */
    @ExceptionHandler(value = BaseException.class)
    @ResponseBody
    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //服务器返回500
    public Object handleBaseException(BaseException e) {
        log.error(e.getMessage(), e);
        if (RequestUtil.isAjax(RequestHolder.getRequest())) {
            return ResponseModel.Failure(e.getMessage(), ((BaseException) e).getCode());
        }
        return ResultUtil.forward("/error/403");
    }
    /**    shiro 没有登录异常    */
    @ExceptionHandler(value = UnauthenticatedException.class)
    @ResponseBody
    // @ResponseStatus(HttpStatus.UNAUTHORIZED) //服务器返回401
    public Object UnauthenticatedException(UnauthenticatedException e) {
        log.error(e.getMessage(), e);
        if (RequestUtil.isAjax(RequestHolder.getRequest())) {
            return ResponseModel.Failure(ResponseEnum.UNAUTHORIZED.getMessage(),ResponseEnum.UNAUTHORIZED.getCode());
        }
        return ResultUtil.forward("/error/401");
    }
    /**    shiro 没有权限异常     */
    @ExceptionHandler(value = UnauthorizedException.class)
    @ResponseBody
    //@ResponseStatus(HttpStatus.FORBIDDEN) //服务器返回500
    public ResponseModel UnauthorizedException(UnauthorizedException e) {
        log.error(e.getMessage(), e);
        return ResponseModel.Failure(ResponseEnum.FORBIDDEN.getMessage(),ResponseEnum.FORBIDDEN.getCode());
    }

    /**
     * MethodArgumentTypeMismatchException ： 方法参数类型异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = NoHandlerFoundException.class)
    @ResponseBody
    public Object notFound(Throwable e) {
        log.error("404 NOT FOUND", e);
        if (RequestUtil.isAjax(RequestHolder.getRequest())) {
            return ResponseModel.Failure(ResponseEnum.NOT_FOUND.getMessage(),ResponseEnum.NOT_FOUND.getCode());
        }
        return ResultUtil.forward("/error/404");
    }
    /**
     * MethodArgumentTypeMismatchException ： 方法参数类型异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public Object methodArgumentTypeMismatchException(Throwable e) {
        log.error("url参数异常，请检查参数类型是否匹配！", e);
        if (RequestUtil.isAjax(RequestHolder.getRequest())) {
            return ResponseModel.Failure(ResponseEnum.PARAM_ERROR.getMessage(),ResponseEnum.PARAM_ERROR.getCode());
        }
        return ResultUtil.forward("/error/400");
    }

    /** 拦截未知的运行时异常，如果需要单独对某个异常处理，可以在外面拿出来，这样会优先执行前面的异常 */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //服务器返回500
    public Object runtimeException(RuntimeException e) {
        /**
         * 如果是正式环境就记录异常信息，有这个必要就可以写。
         */
        if (ENV_PROD.equals(profile)) {
            ResultExceptionAdvice resultExceptionAdvice = SpringContextUtil.getBean(ResultExceptionAdvice.class);
            resultExceptionAdvice.runtimeException(e);
        }
        if (RequestUtil.isAjax(RequestHolder.getRequest())) {
            return ResponseModel.Failure(ResponseEnum.ERROR.getMessage(),ResponseEnum.ERROR.getCode());
        }
        log.error("【系统异常】", e);
        String message = e.getMessage();
       /* return ResponseModel.Failure(message == null || message.trim().isEmpty() ?
                ResponseEnum.ERROR.getMessage() : message,ResponseEnum.ERROR.getCode());*/
        return ResultUtil.forward("/error/500?error="+message);
    }

    /*@ResponseBody
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //服务器返回500
    public ResponseModel errorHandler(Exception ex) {
        log.error(ex.getMessage(),ex);
        ResponseModel rp = new ResponseModel();
        // 根据不同错误获取错误信息
       if (ex instanceof UnauthorizedException) {
            return ResponseModel.Failure("没有访问权限", 403);
        } else {
            String message = ex.getMessage();
            log.error(ex.getMessage(), ex);
            return ResponseModel.Failure(message == null || message.trim().isEmpty() ? "系统错误" : message,500);
        }
    }*/

}
